iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 23
0
Modern Web

Angular新手村學習筆記(2019)系列 第 23

Day23_RxJS 運算子全面解析(1/2)

  • 分享至 

  • xImage
  •  

延申閱讀

RxJS各operators的marble圖
https://rxmarbles.com/
2019 ng conf
RXJS Operators in 20 minutes | Mike Brocchi & John Niedzwiecki
https://www.youtube.com/watch?v=ak3MvMn8u18&list=PLOETEcp3DkCpimylVKTDe968yNmNIajlR&index=48

[S05E06] RxJS 運算子全面解析
https://www.youtube.com/watch?v=DPyZq74V60o&list=PL9LUW6O9WZqgUMHwDsKQf3prtqVvjGZ6S&index=17

今天由Will保哥分享,很多時間是大家在想operator的實際應用
這一集片長2個小時,所以拆成2天po

投影片找不到,所以手搭一下第1頁

很精簡的練習環境

npm i -g webpack webpack-cli webpack-command lite-server typescript
npm init -y
tsc --init
npm i rxjs ts-loader typescript
mkdir src
mkdir src
  1. src/index.ts
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
let ob = of(1,2,3);
ob.pipe(map(v => v*5))
    .subscribe(v => console.log(v));
  1. src/index.html
html:5 snippet
<!DOCTYPE html>
<html lang="zh-Hant-TW"> 如果用en的話,chrome會跳出要不要翻譯
<head>
    <meta charset="UTF-8">
    <meta name="viewport content="width=device-width, initial-scale=1.0, 
                minimum-scale=1, maximum-scale=1"> 
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^避免手機的browser快速點2下就放大
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="dist/bundle.js"></script>
</head>
<body>
</body>
</html>

3.webpack.config.js

module.export = {
    entry: {
        vendor: "./src/index.ts"
    },
    mode: "development",
    module: { 
        rules:[
                {
                    test: /\.tsx?$/,
                               ^^ tsx是react,?代表option 非必要,ts、tsx皆處理
                    loader: 'ts-loader'
                }
            ] 
        },
    plugins:[
    ],
    output:{ 編譯到dist/bundle.js讓index.html引入
      filename: "bundle.js",
    },
    resolve:{
        extensions: ['.js','.jsx','.ts','.tsx']
    },
}

以上設好環境就,就可以上路啦~
設不起來,用Angular專案也能玩

wp -w
lite-server # 存檔立刻看結果

VS Code 安裝 Quokka.js

以前都裝失敗,這一次竟然成功了,開心~
不知道跟wallaby有什麼不同?

VS Code 安裝 Quokka.js Extension

npm i -g typescript
npm init -y
tsc --init
npm i rxjs

牛刀小試

index.js

import { of } from 'rxjs';
import { filter } from 'rxjs/operators';
// 1. of餵數列
var ob = of(1,2,3,4,5); // 建一個最簡單的observable
         ^^ 屬於建立observable的operator,直接把數列轉為observable

// 2. of餵array
var items = [1,2,3,4,5];
var ob2 = of(...items);

ob.subscribe((v) => {
    console.log(v);
});

// 轉成observable後可以做很多操作,語法簡潔、語意好懂
// 範例1:做filter,用pipe再接operator
ob.pipe( // pipe是著跟observable的型別走,不用import
    filter((v) => (v % 2 == 0)
)

後面的程式碼就打面斷囉

fromEvent

https://rxjs-dev.firebaseapp.com/api/index/function/fromEvent
把DOM EventTarget轉成Observable
轉成observable,再subject取得event的資料流後,就可以做超多事!!

fromEvent<T>(target: FromEventTarget<T>, eventName: string, options?: EventListenerOptions
                     ^^^^^^^^^^^^^^^^^^ DOM EventTarget
| ((...args: any[]) => T), resultSelector?: ((...args: any[]) => T)): Observable<T>

// 最常用的就前面2個參數 target: FromEventTarget<T>, eventName: string

// 官網範例
import { fromEvent } from 'rxjs';

// 把document的click event轉成observable
const clicks$ = fromEvent(document, 'click');
            ^加$較好分辨   ^^^^^^^^   ^^^^^
clicks$.subscribe(x => console.log(x));

感謝will保哥重要科普(不會的賺到囉)

  • 觀查MouseEvent
    在chrome的console可以觀查event事件 這個object 及其上層object
    每一層的object都有不同的屬性方法,可以查文件,進而利用
// MouseEvent
f MouseEvent() { [native code] }
^ 是一個function

// MouseEvent.__proto__
             ^^^^^^^^^ 上一層的object
f UIEvent() { [native code] }
  ^^^^^^^ 是UIEvent()
  
// MouseEvent.__proto__.__proto__ 上一層的上一層object  
f Event() { [native code] }

// MouseEvent.__proto__.__proto__.__proto__  
f() { [native code] }
  • 觀查document(window下的一個屬性)
// document
#document

// document.__proto__ 
HTMLDocument {constructor:f, Symbol(Symbol.toStringTag):"HTMLDocument"}
^^^^^^^^^^^^ 所有document都繼承HTMLDocument

// document.__proto__.__proto__
Document {...}

// document.__proto__.__proto__.__proto__
Node {ELEMENT_NODE:1, ATTRIBUTE_NODE:2, TEXT_NODE:3, ...}
^^^^ 一個網頁的節點

// document.__proto__.__proto__.__proto__.__proto__
EventTarget {addEventListener:f, removeEventListener:f, ...}
^^^^^^^^^^^ 所有DOM往上找都會有EventTarget

fromEvent<T>(target: FromEventTarget<T>,...
                         ^^^^^^^^^^^ 所有型別都會有的EventTarget,就是指這個

// document.__proto__.__proto__.__proto__.__proto__.__proto__
{constructor:f, __defineGetter__:f, __defineSetter__:f,...}
(root)根物件

from()

類似of(),差別在於from可以直接傳入array
from([10,20,30])

https://rxjs-dev.firebaseapp.com/api/index/function/from
Creates an Observable from an Array, an array-like object, a Promise, an iterable object, or an Observable-like object.

from<T>(input: ObservableInput<T>, scheduler?: SchedulerLike): Observable<T>
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^

fromPromise()好像不見了,官網文件找不到
可能是RxJS6拿掉了,想看只能到舊文件找了
https://cn.rx.js.org/class/es6/Observable.js~Observable.html#static-method-fromPromise

var ob = from(fetch('data.json'));
               ^^^^^ fetch()可以用.json()轉json
// data.json {id:1, name:"Will"}

ob.pipe().subscribe((v:any)=>{
    var ob2 = from(v.json());
                   ^^^^^^^^ 回傳promise
    ob2.subscribe((xx:any)=>{
        console.log(xx.json());
    })
});

然後… create()運算子也沒了…
變成Observable.create()

bindCallback

https://rxjs-dev.firebaseapp.com/api/index/function/bindCallback

傳入callback function,會自動把callback function轉成observable

Converts a callback API to a function that returns an Observable.

bindCallback<T>(callbackFunc: Function, resultSelector?: Function | SchedulerLike, scheduler?: SchedulerLike): (...args: any[]) => Observable<T>

官網範例

import { bindCallback } from 'rxjs';
import * as jQuery from 'jquery';

// Suppose we have jQuery.getJSON('/my/url', callback)
// 只要callbackFunc的signature用法是 ^^^^^^ 配 ^^^^^^ callback function
// 就可以用bindCallback來binding
const getJSONAsObservable = bindCallback(jQuery.getJSON);
                                                ^^^^^^^ 這是function
const result = getJSONAsObservable('/my/url');
result.subscribe(x => console.log(x), e => console.error(e));

repeat()

https://rxjs-dev.firebaseapp.com/api/operators/repeat

Returns an Observable that will resubscribe to the source stream when the source stream completes, at most count times.

repeat<T>(count: number = -1): MonoTypeOperatorFunction<T>
^^^^^ 會重覆的subscribe n次

(a)--(b)--(complete)
如果count=3的話
會變成重覆3次
(a)--(b)--(a)--(b)--(a)--(b)--(complete)

defer()

https://rxjs-dev.firebaseapp.com/api/index/function/defer

Creates an Observable that, on subscribe, calls an Observable factory to make an Observable for each new Observer.

defer<R extends ObservableInput<any> | void>(observableFactory: () => R): Observable<ObservedValueOf<R>>

  • 官網範例
import { defer, fromEvent, interval } from 'rxjs';
 
const clicksOrInterval = defer(function () {
                               ^^^^^^^^^^^ 放一個callback function
                                           Observable factory
  return Math.random() > 0.5
    ? fromEvent(document, 'click')
    : interval(1000);
});
clicksOrInterval.subscribe(x => console.log(x));
                 ^^^^^^^^^ 有observer訂閱的時候,就各別呼叫Observable factory
                           產生observable給observer

上一篇
Day22_Observable & RxJS in Angular
下一篇
Day24_RxJS 運算子全面解析(2/2)
系列文
Angular新手村學習筆記(2019)33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言